home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkGC.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  10KB  |  364 lines

  1. /* 
  2.  * tkGC.c --
  3.  *
  4.  *    This file maintains a database of read-only graphics contexts 
  5.  *    for the Tk toolkit, in order to allow GC's to be shared.
  6.  *
  7.  * Copyright (c) 1990-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  */
  13.  
  14. static char sccsid[] = "@(#) tkGC.c 1.17 95/03/17 16:01:54";
  15.  
  16. #include "tkPort.h"
  17. #include "tk.h"
  18.  
  19. /*
  20.  * One of the following data structures exists for each GC that is
  21.  * currently active.  The structure is indexed with two hash tables,
  22.  * one based on the values in the graphics context and the other
  23.  * based on the display and GC identifier.
  24.  */
  25.  
  26. typedef struct {
  27.     GC gc;            /* Graphics context. */
  28.     Display *display;        /* Display to which gc belongs. */
  29.     int refCount;        /* Number of active uses of gc. */
  30.     Tcl_HashEntry *valueHashPtr;/* Entry in valueTable (needed when deleting
  31.                  * this structure). */
  32. } TkGC;
  33.  
  34. /*
  35.  * Hash table to map from a GC's values to a TkGC structure describing
  36.  * a GC with those values (used by Tk_GetGC).
  37.  */
  38.  
  39. static Tcl_HashTable valueTable;
  40. typedef struct {
  41.     XGCValues values;        /* Desired values for GC. */
  42.     Display *display;        /* Display for which GC is valid. */
  43.     int screenNum;        /* screen number of display */
  44.     int depth;            /* and depth for which GC is valid. */
  45. } ValueKey;
  46.  
  47. /*
  48.  * Hash table for <display + GC> -> TkGC mapping. This table is used by
  49.  * Tk_FreeGC.
  50.  */
  51.  
  52. static Tcl_HashTable idTable;
  53. typedef struct {
  54.     Display *display;        /* Display for which GC was allocated. */
  55.     GC gc;            /* X's identifier for GC. */
  56. } IdKey;
  57.  
  58. static int initialized = 0;    /* 0 means static structures haven't been
  59.                  * initialized yet. */
  60.  
  61. /*
  62.  * Forward declarations for procedures defined in this file:
  63.  */
  64.  
  65. static void        GCInit _ANSI_ARGS_((void));
  66.  
  67. /*
  68.  *----------------------------------------------------------------------
  69.  *
  70.  * Tk_GetGC --
  71.  *
  72.  *    Given a desired set of values for a graphics context, find
  73.  *    a read-only graphics context with the desired values.
  74.  *
  75.  * Results:
  76.  *    The return value is the X identifer for the desired graphics
  77.  *    context.  The caller should never modify this GC, and should
  78.  *    call Tk_FreeGC when the GC is no longer needed.
  79.  *
  80.  * Side effects:
  81.  *    The GC is added to an internal database with a reference count.
  82.  *    For each call to this procedure, there should eventually be a call
  83.  *    to Tk_FreeGC, so that the database can be cleaned up when GC's
  84.  *    aren't needed anymore.
  85.  *
  86.  *----------------------------------------------------------------------
  87.  */
  88.  
  89. GC
  90. Tk_GetGC(tkwin, valueMask, valuePtr)
  91.     Tk_Window tkwin;        /* Window in which GC will be used. */
  92.     register unsigned long valueMask;
  93.                 /* 1 bits correspond to values specified
  94.                  * in *valuesPtr;  other values are set
  95.                  * from defaults. */
  96.     register XGCValues *valuePtr;
  97.                 /* Values are specified here for bits set
  98.                  * in valueMask. */
  99. {
  100.     ValueKey valueKey;
  101.     IdKey idKey;
  102.     Tcl_HashEntry *valueHashPtr, *idHashPtr;
  103.     register TkGC *gcPtr;
  104.     int new;
  105.     Drawable d, freeDrawable;
  106.  
  107.     if (!initialized) {
  108.     GCInit();
  109.     }
  110.  
  111.     /*
  112.      * Must zero valueKey at start to clear out pad bytes that may be
  113.      * part of structure on some systems.
  114.      */
  115.  
  116.     memset((VOID *) &valueKey, 0, sizeof(valueKey));
  117.  
  118.     /*
  119.      * First, check to see if there's already a GC that will work
  120.      * for this request (exact matches only, sorry).
  121.      */
  122.  
  123.     if (valueMask & GCFunction) {
  124.     valueKey.values.function = valuePtr->function;
  125.     } else {
  126.     valueKey.values.function = GXcopy;
  127.     }
  128.     if (valueMask & GCPlaneMask) {
  129.     valueKey.values.plane_mask = valuePtr->plane_mask;
  130.     } else {
  131.     valueKey.values.plane_mask = (unsigned) ~0;
  132.     }
  133.     if (valueMask & GCForeground) {
  134.     valueKey.values.foreground = valuePtr->foreground;
  135.     } else {
  136.     valueKey.values.foreground = 0;
  137.     }
  138.     if (valueMask & GCBackground) {
  139.     valueKey.values.background = valuePtr->background;
  140.     } else {
  141.     valueKey.values.background = 1;
  142.     }
  143.     if (valueMask & GCLineWidth) {
  144.     valueKey.values.line_width = valuePtr->line_width;
  145.     } else {
  146.     valueKey.values.line_width = 0;
  147.     }
  148.     if (valueMask & GCLineStyle) {
  149.     valueKey.values.line_style = valuePtr->line_style;
  150.     } else {
  151.     valueKey.values.line_style = LineSolid;
  152.     }
  153.     if (valueMask & GCCapStyle) {
  154.     valueKey.values.cap_style = valuePtr->cap_style;
  155.     } else {
  156.     valueKey.values.cap_style = CapButt;
  157.     }
  158.     if (valueMask & GCJoinStyle) {
  159.     valueKey.values.join_style = valuePtr->join_style;
  160.     } else {
  161.     valueKey.values.join_style = JoinMiter;
  162.     }
  163.     if (valueMask & GCFillStyle) {
  164.     valueKey.values.fill_style = valuePtr->fill_style;
  165.     } else {
  166.     valueKey.values.fill_style = FillSolid;
  167.     }
  168.     if (valueMask & GCFillRule) {
  169.     valueKey.values.fill_rule = valuePtr->fill_rule;
  170.     } else {
  171.     valueKey.values.fill_rule = EvenOddRule;
  172.     }
  173.     if (valueMask & GCArcMode) {
  174.     valueKey.values.arc_mode = valuePtr->arc_mode;
  175.     } else {
  176.     valueKey.values.arc_mode = ArcPieSlice;
  177.     }
  178.     if (valueMask & GCTile) {
  179.     valueKey.values.tile = valuePtr->tile;
  180.     } else {
  181.     valueKey.values.tile = None;
  182.     }
  183.     if (valueMask & GCStipple) {
  184.     valueKey.values.stipple = valuePtr->stipple;
  185.     } else {
  186.     valueKey.values.stipple = None;
  187.     }
  188.     if (valueMask & GCTileStipXOrigin) {
  189.     valueKey.values.ts_x_origin = valuePtr->ts_x_origin;
  190.     } else {
  191.     valueKey.values.ts_x_origin = 0;
  192.     }
  193.     if (valueMask & GCTileStipYOrigin) {
  194.     valueKey.values.ts_y_origin = valuePtr->ts_y_origin;
  195.     } else {
  196.     valueKey.values.ts_y_origin = 0;
  197.     }
  198.     if (valueMask & GCFont) {
  199.     valueKey.values.font = valuePtr->font;
  200.     } else {
  201.     valueKey.values.font = None;
  202.     }
  203.     if (valueMask & GCSubwindowMode) {
  204.     valueKey.values.subwindow_mode = valuePtr->subwindow_mode;
  205.     } else {
  206.     valueKey.values.subwindow_mode = ClipByChildren;
  207.     }
  208.     if (valueMask & GCGraphicsExposures) {
  209.     valueKey.values.graphics_exposures = valuePtr->graphics_exposures;
  210.     } else {
  211.     valueKey.values.graphics_exposures = True;
  212.     }
  213.     if (valueMask & GCClipXOrigin) {
  214.     valueKey.values.clip_x_origin = valuePtr->clip_x_origin;
  215.     } else {
  216.     valueKey.values.clip_x_origin = 0;
  217.     }
  218.     if (valueMask & GCClipYOrigin) {
  219.     valueKey.values.clip_y_origin = valuePtr->clip_y_origin;
  220.     } else {
  221.     valueKey.values.clip_y_origin = 0;
  222.     }
  223.     if (valueMask & GCClipMask) {
  224.     valueKey.values.clip_mask = valuePtr->clip_mask;
  225.     } else {
  226.     valueKey.values.clip_mask = None;
  227.     }
  228.     if (valueMask & GCDashOffset) {
  229.     valueKey.values.dash_offset = valuePtr->dash_offset;
  230.     } else {
  231.     valueKey.values.dash_offset = 0;
  232.     }
  233.     if (valueMask & GCDashList) {
  234.     valueKey.values.dashes = valuePtr->dashes;
  235.     } else {
  236.     valueKey.values.dashes = 4;
  237.     }
  238.     valueKey.display = Tk_Display(tkwin);
  239.     valueKey.screenNum = Tk_ScreenNumber(tkwin);
  240.     valueKey.depth = Tk_Depth(tkwin);
  241.     valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &valueKey, &new);
  242.     if (!new) {
  243.     gcPtr = (TkGC *) Tcl_GetHashValue(valueHashPtr);
  244.     gcPtr->refCount++;
  245.     return gcPtr->gc;
  246.     }
  247.  
  248.     /*
  249.      * No GC is currently available for this set of values.  Allocate a
  250.      * new GC and add a new structure to the database.
  251.      */
  252.  
  253.     gcPtr = (TkGC *) ckalloc(sizeof(TkGC));
  254.  
  255.     /*
  256.      * Find or make a drawable to use to specify the screen and depth
  257.      * of the GC.  We may have to make a small pixmap, to avoid doing
  258.      * Tk_MakeWindowExist on the window.
  259.      */
  260.  
  261.     freeDrawable = None;
  262.     if (Tk_WindowId(tkwin) != None) {
  263.     d = Tk_WindowId(tkwin);
  264.     } else if (valueKey.depth ==
  265.         DefaultDepth(valueKey.display, valueKey.screenNum)) {
  266.     d = RootWindow(valueKey.display, valueKey.screenNum);
  267.     } else {
  268.     d = Tk_GetPixmap(valueKey.display,
  269.         RootWindow(valueKey.display, valueKey.screenNum),
  270.         1, 1, valueKey.depth);
  271.     freeDrawable = d;
  272.     }
  273.  
  274.     gcPtr->gc = XCreateGC(valueKey.display, d, valueMask, &valueKey.values);
  275.     gcPtr->display = valueKey.display;
  276.     gcPtr->refCount = 1;
  277.     gcPtr->valueHashPtr = valueHashPtr;
  278.     idKey.display = valueKey.display;
  279.     idKey.gc = gcPtr->gc;
  280.     idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new);
  281.     if (!new) {
  282.     panic("GC already registered in Tk_GetGC");
  283.     }
  284.     Tcl_SetHashValue(valueHashPtr, gcPtr);
  285.     Tcl_SetHashValue(idHashPtr, gcPtr);
  286.     if (freeDrawable != None) {
  287.     Tk_FreePixmap(valueKey.display, freeDrawable);
  288.     }
  289.  
  290.     return gcPtr->gc;
  291. }
  292.  
  293. /*
  294.  *----------------------------------------------------------------------
  295.  *
  296.  * Tk_FreeGC --
  297.  *
  298.  *    This procedure is called to release a graphics context allocated by
  299.  *    Tk_GetGC.
  300.  *
  301.  * Results:
  302.  *    None.
  303.  *
  304.  * Side effects:
  305.  *    The reference count associated with gc is decremented, and
  306.  *    gc is officially deallocated if no-one is using it anymore.
  307.  *
  308.  *----------------------------------------------------------------------
  309.  */
  310.  
  311. void
  312. Tk_FreeGC(display, gc)
  313.     Display *display;        /* Display for which gc was allocated. */
  314.     GC gc;            /* Graphics context to be released. */
  315. {
  316.     IdKey idKey;
  317.     Tcl_HashEntry *idHashPtr;
  318.     register TkGC *gcPtr;
  319.  
  320.     if (!initialized) {
  321.     panic("Tk_FreeGC called before Tk_GetGC");
  322.     }
  323.  
  324.     idKey.display = display;
  325.     idKey.gc = gc;
  326.     idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey);
  327.     if (idHashPtr == NULL) {
  328.     panic("Tk_FreeGC received unknown gc argument");
  329.     }
  330.     gcPtr = (TkGC *) Tcl_GetHashValue(idHashPtr);
  331.     gcPtr->refCount--;
  332.     if (gcPtr->refCount == 0) {
  333.     Tk_FreeXId(gcPtr->display, (XID) XGContextFromGC(gcPtr->gc));
  334.     XFreeGC(gcPtr->display, gcPtr->gc);
  335.     Tcl_DeleteHashEntry(gcPtr->valueHashPtr);
  336.     Tcl_DeleteHashEntry(idHashPtr);
  337.     ckfree((char *) gcPtr);
  338.     }
  339. }
  340.  
  341. /*
  342.  *----------------------------------------------------------------------
  343.  *
  344.  * GCInit --
  345.  *
  346.  *    Initialize the structures used for GC management.
  347.  *
  348.  * Results:
  349.  *    None.
  350.  *
  351.  * Side effects:
  352.  *    Read the code.
  353.  *
  354.  *----------------------------------------------------------------------
  355.  */
  356.  
  357. static void
  358. GCInit()
  359. {
  360.     initialized = 1;
  361.     Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int));
  362.     Tcl_InitHashTable(&idTable, sizeof(IdKey)/sizeof(int));
  363. }
  364.